package com.android.yummycookies.model.commonModel;

import android.graphics.Canvas;
import android.view.SurfaceHolder;

import com.android.yummycookies.commonInterface.IGameEngine;

public class GameLoop<T extends IGameEngine> extends Thread {
	
	/** Flag permetant d'arreter le thread */
	private boolean running = false;

	/** Holder sur la surface d'affichage */
	private SurfaceHolder surfaceHolder;

	/** Nombre maximal de frame par seconde */
	private int maxFPS = 30;
	/** Duree d'une frame */
	private int framePeriod = 1000 / maxFPS;
	/**
	 * Nombre de frame a sauter si la mise a jour
	 * du jeu prend du retard
	 */
	private final int maxFrameSkips = 5;

	/** 
	 * Moteur de jeu
	 */
	T gameEngine;
	
	public GameLoop(T gameEngine, SurfaceHolder surfaceHolder) {
		this.gameEngine = gameEngine;
		this.surfaceHolder = surfaceHolder;
	}

	@Override
	public void run() {
		// reference au canevas lie au holder
		Canvas canvas;

		// temps de debut de cycle
		long beginTime = 0;
		// temps d'execution d'un cycle
		long timeDiff = 0;
		// temps de sommeil si mis a jour rapide
		int sleepTime = 0;
		// nombre de frame saute en cas de retard sur
		// la mise a jour
		int framesSkipped = 0;

		while (running) {
			canvas = null;

			try {
				// recuperation du canevas
				canvas = this.surfaceHolder.lockCanvas();
				// lock le holder pour dessiner
				synchronized (surfaceHolder) {
					// recuperation du temps courant
					beginTime = System.currentTimeMillis();

					// mis a jour du jeu
					gameEngine.update();
					// affichage du jeu
					gameEngine.draw(canvas);

					// calcule du temps de cycle
					timeDiff = System.currentTimeMillis() - beginTime;
					// calcule du temps de sommeil
					sleepTime = (int) (framePeriod - timeDiff);

					// met en pause le thread si necessaire
					if (sleepTime > 0) {
						try {
							Thread.sleep(sleepTime);
						} catch (InterruptedException e) {
						}
					}

					// tant qu'on est en avance, on saute des affichages
					// et on met a jour le jeu
					while (sleepTime < 0 && framesSkipped < maxFrameSkips) {
						this.gameEngine.update();
						sleepTime += framePeriod;
						framesSkipped++;
					}
				}
			} finally {
				if (canvas != null) {
					surfaceHolder.unlockCanvasAndPost(canvas);
				}
			}
		}
	}

	public boolean isRunning() {
		return running;
	}
	
	public void setRunning(boolean running) {
		this.running = running;
	}
	
	public int getMaxFPS() {
		return maxFPS;
	}

	public void setMaxFPS(int maxFPS) {
		this.maxFPS = maxFPS;
	}

	public int getFramePeriod() {
		return framePeriod;
	}

	public int getMaxFrameSkips() {
		return maxFrameSkips;
	}

}
